package edu.pku.hawk.sandbox;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeoutException;

import javax.jms.JMSException;
import javax.jms.MessageListener;


import edu.pku.hawk.controller.detectmonitor.DetectReport;
import edu.pku.hawk.controller.util.Constants;
import edu.pku.hawk.controller.util.InvadeReport;
import edu.pku.hawk.controller.util.MConsumerQueue;
import edu.pku.hawk.controller.util.MQManager;
import edu.pku.hawk.controller.util.MQueue;
import edu.pku.hawk.controller.util.RegionPath;
import edu.pku.hawk.controller.util.SubjectDescription;
import flex.messaging.MessageBroker;
import flex.messaging.messages.AsyncMessage;
import flex.messaging.messages.Message;
import flex.messaging.services.MessageService;
import flex.messaging.services.ServiceAdapter;
import flex.messaging.util.UUIDUtils;

/**
 * 
 * This class is used to get sensor data message from the jms queue and send to
 * the UI TODO: 1 complete the code that get from the jsm queue 2 complete the
 * code that get the subject code from webservice 3 change the name of this
 * class
 * 
 * @author power
 * 
 */
public class ListOfDifferentMessageAdapter extends ServiceAdapter {
	
	private static String TAND_ID = "TANK";

	DataSender thread;

	Random random;
	SubjectDescription[] subjects;
	
	Object[] subjectsLock=new Object[0];

	public ListOfDifferentMessageAdapter() {
		random = new Random();
	}

	public ArrayList receivedMessage = new ArrayList();

	public Object msgLock = new Object();

	public void start() {
		if (thread == null) {
			System.out.println("Adapter started");
			listenQueue();
		}
	}

	public void stop() {
		System.out.println("Adapter stopped");
		thread.running = false;
		thread = null;
	}

	/**
	 * here we listen the queue and send message to the UI
	 */
	public void listenQueue() {
		MQManager mgr = null;
		try {
			mgr = MQManager.getInstance();
			MConsumerQueue queue = mgr
					.getConsumerQueue(Constants.Ctrl_UI_Sensor_QueueName);

			final String clientId = UUIDUtils.createUUID();
			final MessageBroker msgBroker = MessageBroker
					.getMessageBroker(null);

			queue.setMessageListener(new MessageListener() {
				@Override
				public void onMessage(javax.jms.Message message) {
					try {
						DetectReport report = (DetectReport) MQueue
								.toOjbect(message);
						
						AsyncMessage msg = new AsyncMessage();
						msg.setDestination("ListOfDifferentMessage");
						msg.setClientId(clientId);
						msg.setMessageId(UUIDUtils.createUUID());
						// get message..
						if(report.dtctType==AppConstant.TYPE_RFID_READER)
						{
							BaseMessage mymsg = new BaseMessage(AppConstant.TYPE_RFID_MESSAGE,
									"" + report.detectorId);
							mymsg.setValue(report.lastValue);
							msg.setBody(mymsg);
							msgBroker.routeMessageToService(msg, null);
						}
						else
						{
							BaseMessage mymsg = new BaseMessage(AppConstant.TYPE_SENSOR_MESSAGE,
									"" + report.detectorId);
							SensorHistoryData data = new SensorHistoryData(""
									+ new Date(report.timeStamp), report.lastValue);
							mymsg.setValue(data);
	
							msg.setBody(mymsg);
							msgBroker.routeMessageToService(msg, null);
						}

					} catch (Exception ex) {
						ex.printStackTrace();
					}
				}
			});

			queue = mgr.getConsumerQueue(Constants.Ctrl_UI_Path_QueueName);
			queue.setMessageListener(new MessageListener() {
				
				@Override
				public void onMessage(javax.jms.Message message) {
					try {

						RegionPath path = (RegionPath) MQueue.toOjbect(message);
						//System.out.println("get path message type:"+path.getLast().objType);
						AsyncMessage msg = new AsyncMessage();
						msg.setDestination("ListOfDifferentMessage");
						msg.setClientId(clientId);
						msg.setMessageId(UUIDUtils.createUUID());
						// here we may have different type of message
						BaseMessage mymsg=null;
						System.out.println("Receive UI Path Type:"+path.objType+" ");
						//if the type_track_tank, it shows the tank
						if(path.objType==AppConstant.TYPE_TRACK_TANK)
						{
							mymsg=  new BaseMessage(AppConstant.TYPE_COMBINATION,"TANK");
							mymsg.setValue(path.getLast());
						}
						//else show a circle
						else if(path.objType==AppConstant.TYPE_TRACK_TRUNK)
						{
							mymsg=  new BaseMessage(path.sensorType,"TANK");
							mymsg.setValue(path.getLast());
						}
						msg.setBody(mymsg);
						msgBroker.routeMessageToService(msg, null);
					} catch (JMSException e) {
						e.printStackTrace();
					}
					
				}
			});
			
			queue = mgr.getConsumerQueue(Constants.Ctrl_UI_Battlefield_QueueName);
			queue.setMessageListener(new MessageListener() {
				
				@Override
				public void onMessage(javax.jms.Message message) {
					try {
						
						synchronized (subjectsLock) {
							subjects = (SubjectDescription[]) MQueue.toOjbect(message);
							System.out.println("receive new subject:"+subjects);
						}
					} catch (JMSException e) {
						e.printStackTrace();
					}
					
				}
			});
			
			queue=mgr.getConsumerQueue(Constants.Ctrl_UI_Alarm_QueueName);
			queue.setMessageListener(new MessageListener() {
				
				@Override
				public void onMessage(javax.jms.Message message) {
					try{
						
						AsyncMessage msg = new AsyncMessage();
						msg.setDestination("ListOfDifferentMessage");
						msg.setClientId(clientId);
						msg.setMessageId(UUIDUtils.createUUID());
						// here we may have different type of message
						BaseMessage mymsg=new BaseMessage(AppConstant.TYPE_INFRARED_MESSAGE,"TANK");
						InvadeReport ir=(InvadeReport) MQueue.toOjbect(message);
						mymsg.setValue(ir);
						msg.setBody(mymsg);
						msgBroker.routeMessageToService(msg, null);
					}catch(JMSException e)
					{
						e.printStackTrace();
					}
					
				}
			});
		} catch (Exception ex) {
			ex.printStackTrace();
			if (mgr != null) {
				try {
					mgr.close();
				} catch (Exception eex) {
					ex.printStackTrace();
				}
			}
		}
	}

	/**
	 * change the data format to the BaseMessage
	 * 
	 * @param report
	 * @return
	 */
	protected BaseMessage ChangeMessageFormat(DetectReport report) {
		// TODO change the detectreport to message

		return null;
	}

	/**
	 * Thread to listen got message from queue to the object.
	 * 
	 * @author power
	 * 
	 */
	public class DataSender extends Thread {
		public boolean running = true;

		public void run() {
			String clientId = UUIDUtils.createUUID();
			MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
			while (running) {
				AsyncMessage msg = new AsyncMessage();
				msg.setDestination("ListOfDifferentMessage");
				msg.setClientId(clientId);
				msg.setMessageId(UUIDUtils.createUUID());
				// get message..
				msg.setBody(getLatestMessage());
				msgBroker.routeMessageToService(msg, null);
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					System.out.println("Exception");
					e.printStackTrace();
				}
			}

		}
	}

	/**
	 * got latest sensor/tank data from the jms message queue
	 * 
	 * @return
	 */

	// public ArrayList getLatestMessage() {
	//		
	// }
	public ArrayList getLatestMessage() {
		// correct code
		// synchronized (msgLock) {
		// ArrayList result=this.receivedMessage;
		// this.receivedMessage=new ArrayList();
		// return result;
		// }
		// correct code end

		// ===================faked
		// code==============================================
		ArrayList list = new ArrayList();
		// ArrayList<BaseMessage> list=new ArrayList<BaseMessage>();
		BaseMessage mymsg = new BaseMessage(AppConstant.TYPE_LOCATION_MESSAGE,
				"sensor1");
		mymsg.setValue(new LocationMessage(random.nextInt(400), random
				.nextInt(300)));
		list.add(mymsg);
		mymsg = new BaseMessage(AppConstant.TYPE_SENSOR_MESSAGE, "sensor2");
		// mymsg.setValue(new BooleanSensorMessage(random.nextBoolean()));

		int value = random.nextInt(100);
		SensorHistoryData data = new SensorHistoryData("" + new Date(), value);
		mymsg.setValue(data);
		list.add(mymsg);
		return list;
		// ==================fake code
		// end============================================

	}

	/**
	 * this class is used to got all the subject description from the web
	 * service
	 * 
	 * @return
	 */
	protected ArrayList getSubjectDescription() {
//		// fake code
//		ArrayList list = new ArrayList();
//		
//		SubjectDescription sd=new SubjectDescription("sdfsdf", AppConstant.TYPE_COMBINATION, 600, 800); 
//		
//		sd= new SubjectDescription("14",
//				AppConstant.TYPE_SOUND_SENSOR, 150, 200);
//		
//		list.add(sd);
//		sd = new SubjectDescription("10",
//				AppConstant.TYPE_PRESSURE_SENSOR, 100, 150);
//		list.add(sd);
//		// make the tank to the latest so the tank will not be covered
//		sd = new SubjectDescription("sensor1", AppConstant.TYPE_TANK, 50, 60);
//		list.add(sd);
//		return list;
//		// fake code end
		
		ArrayList subjectList = new ArrayList();
		
		if(this.subjects!=null){
			synchronized (subjectsLock) {
				for(int i=0;i<subjects.length;i++){
					subjectList.add(subjects[i]);
				}
			}
		}else{
			SubjectDescription sub = new SubjectDescription("0",AppConstant.TYPE_UNKNOWN,900,600);
			subjectList.add(sub);
		}
		SubjectDescription tank = new SubjectDescription("TANK", AppConstant.TYPE_TANK, 0, 0);
		subjectList.add(tank);
		System.out.println("::::::"+subjectList);
		return subjectList;
	}

	@Override
	public Object invoke(Message msg) {
		if (msg.getBody()!=null && msg.getBody().equals("GetInitialObjects")) {
			System.out.println("Adapter received GetInitialObjects Cmd");
			return getSubjectDescription();
		} else {
			//System.out.println("Adapter sending message");
			AsyncMessage newMessage = (AsyncMessage) msg;
			MessageService msgService = (MessageService) getDestination()
					.getService();
			msgService.pushMessageToClients(newMessage, true);
		}
		return null;
	}

}
